package com.google.coffeeshop.business;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import javax.persistence.EntityManager;
import javax.swing.JOptionPane;

import com.google.coffeeshop.GeneralConstants;
import com.google.coffeeshop.dao.DAOFactory;
import com.google.coffeeshop.dao.EmployeeDAO;
import com.google.coffeeshop.dao.InvoiceDAO;
import com.google.coffeeshop.dao.OrderDAO;
import com.google.coffeeshop.dao.ProductDAO;
import com.google.coffeeshop.dao.ReceiptNoteDAO;
import com.google.coffeeshop.entity.EmployeeDTO;
import com.google.coffeeshop.entity.InvoiceDTO;
import com.google.coffeeshop.entity.InvoiceLineDTO;
import com.google.coffeeshop.entity.OrderDTO;
import com.google.coffeeshop.entity.OrderLineDTO;
import com.google.coffeeshop.entity.ProductDTO;
import com.google.coffeeshop.entity.ReceiptNoteDTO;
import com.google.coffeeshop.entity.ReceiptNoteLineDTO;
import com.google.coffeeshop.entity.SaleIncome;

public class StatisticsBusiness extends AbstractBaseBusiness {

	public static List<SaleIncome> getSaleBetweenDates(Date beginDate,
			Date endDate, EmployeeDTO employee, ProductDTO product) {
		final List<SaleIncome> saleIncomes = new ArrayList<SaleIncome>();
		final EntityManager entityManager = createEntityManager();
		Calendar begin = Calendar.getInstance();
		Calendar end = Calendar.getInstance();
		begin.setTime(beginDate);
		end.setTime(beginDate);
		end.set(Calendar.DAY_OF_MONTH,
				begin.getActualMaximum(Calendar.DAY_OF_MONTH));
		while (end.getTime().before(endDate)) {
			SaleIncome saleIncome = createSalesIncome(begin, end, employee, product, entityManager);
			saleIncomes.add(saleIncome);
			
			begin = (Calendar)end.clone();
			begin.add(Calendar.DAY_OF_MONTH, 1);
			
			end = (Calendar)begin.clone();
			end.set(Calendar.DAY_OF_MONTH,
					begin.getActualMaximum(Calendar.DAY_OF_MONTH));
		}
		end.setTime(endDate);
		final SaleIncome saleIncome = createSalesIncome(begin, end, employee, product, entityManager);
		saleIncomes.add(saleIncome);
		return saleIncomes;
	}

	public static List<ProductDTO> getProductsSoldBetweenDates(Long productId,
			Date beginDate, Date endDate) {
		final List<ProductDTO> productsSold = new ArrayList<ProductDTO>();
		
		final EntityManager entityManager = createEntityManager();
		final List<ProductDTO> activeProducts = new ArrayList<ProductDTO>();
		if (null != productId && productId != 0) {
			activeProducts.add(getActiveProductById(productId, entityManager));
		} else {
			activeProducts.addAll(getAllActiveProducts(entityManager));
		}
		
		final List<OrderDTO> orders2Calc = getOrdersBetweenDates(beginDate, endDate,
				entityManager);
		
		if (activeProducts != null && !activeProducts.isEmpty()) {
			for (ProductDTO product : activeProducts) {
				Long quantity = getSoldQuantityOfProduct(product.getId(), orders2Calc);
				if (null != quantity && quantity != 0) {
					product.setInventory(quantity);
					productsSold.add(product);
				}
			}
		}
		return productsSold;
	}
	
	public static List<ProductDTO> getProductsStoredBetweenDates(Long productId,
			Date beginDate, Date endDate) {
		final List<ProductDTO> productsStored = new ArrayList<ProductDTO>(); 
		
		final EntityManager entityManager = createEntityManager();
		
		final List<ProductDTO> activeProducts = new ArrayList<ProductDTO>();
		if (null != productId && productId != 0) {
			activeProducts.add(getActiveProductById(productId, entityManager));
		} else {
			activeProducts.addAll(getAllActiveProducts(entityManager));
		}
		
		
		final List<ReceiptNoteDTO> receiptNotes2Calc = getReceiptNotesBetweenDates(
				beginDate, endDate, entityManager);
		if (activeProducts != null && !activeProducts.isEmpty()) {
			for (ProductDTO product : activeProducts) {
				Long quantity = getStoredQuantityOfProduct(product.getId(), receiptNotes2Calc);
				if (null != quantity && quantity != 0) {
					product.setInventory(quantity);
					productsStored.add(product);
				}
			}
		}
		return productsStored;
	}
	
	public static List<ProductDTO> getInventoryByDate(Long productId, Date date) {
		final List<ProductDTO> productsWithInventory = new ArrayList<ProductDTO>();
		
		final EntityManager entityManager = createEntityManager();
		
		final List<ProductDTO> activeProducts = new ArrayList<ProductDTO>();
		if (null != productId && productId != 0) {
			activeProducts.add(getActiveProductById(productId, entityManager));
		} else {
			activeProducts.addAll(getAllActiveProducts(entityManager));
		}
		
		final List<OrderDTO> orders2Calc = getOrdersByDate(date, entityManager);
		final List<ReceiptNoteDTO> receiptNotes2Calc = getReceiptNotesByDate(date,
				entityManager);
		Long quantity;
		if (activeProducts != null && !activeProducts.isEmpty()) {
			for (ProductDTO product : activeProducts) {
				quantity = getInventoryOfProduct(product.getId(), receiptNotes2Calc, orders2Calc);
				if (null != quantity && quantity != 0) {
					product.setInventory(quantity);
					productsWithInventory.add(product);
				}
			}
		}
		return productsWithInventory;
	}
	
	private static SaleIncome createSalesIncome(Calendar begin, Calendar end, EmployeeDTO employee, ProductDTO product, EntityManager entityManager) {
		long income=0;
		final long sales = calculateTotalSales(begin.getTime(), end.getTime(), employee, product, entityManager);
		if(employee == null){
			final long funds = calculateTotalFunds(begin.getTime(), end.getTime(), entityManager);
			income = sales - funds;
		}
		return new SaleIncome(sales, income,begin.getTime());
	}
	
	private static long calculateTotalSales(Date beginDate, Date endDate, EmployeeDTO employee, ProductDTO product, EntityManager entityManager) {
		long sumSales = 0L;  
		final List<InvoiceDTO> invoicesPaid = getInvoicesBetweenDates(beginDate, endDate,
				GeneralConstants.INVOICE_PAID_STATUS, employee, entityManager);
		if (invoicesPaid != null && !invoicesPaid.isEmpty()) {
			for (InvoiceDTO invoice : invoicesPaid) {
				if(product == null)
					sumSales += invoice.getAmount();
				else for(InvoiceLineDTO invoiceLine : invoice.getInvoiceLines())
						if(invoiceLine.getOrderLine().getProduct().getId() == product.getId())
							sumSales+= invoiceLine.getOrderLine().getQuantity()*invoiceLine.getOrderLine().getQuantity();
			}
		}
		return sumSales;
	}
	
	private static long calculateTotalFunds(Date beginDate, Date endDate, EntityManager entityManager) {
		long sumFunds = 0L;  
		final List<ReceiptNoteDTO> receiptNotes = getReceiptNotesBetweenDates(beginDate, endDate, entityManager);
		if (receiptNotes != null && !receiptNotes.isEmpty()) {
			for (ReceiptNoteDTO receiptNote : receiptNotes) {
				sumFunds += receiptNote.getAmount();
			}
		}
		return sumFunds;
	}
	
	private static Long getSoldQuantityOfProduct(Long productId, List<OrderDTO> orders2Calc) {
		Long quantity = 0L;
		for (OrderDTO order : orders2Calc) {
			for (OrderLineDTO orderLine : order.getOrderLines()) {
				if (productId == orderLine.getProduct().getId()) {
					quantity += orderLine.getQuantity();
				}
			}
		}
		return quantity;
	}
	
	private static Long getStoredQuantityOfProduct(Long productId, List<ReceiptNoteDTO> receiptNotes2Calc) {
		Long quantity = 0L;
		for (ReceiptNoteDTO receiptNote : receiptNotes2Calc) {
			for (ReceiptNoteLineDTO receiptNoteLine : receiptNote
					.getReceiptNoteLines()) {
				if (productId == receiptNoteLine.getProduct()
						.getId()) {
					quantity += receiptNoteLine.getQuantity();
				}
			}
		}
		return quantity;
	}
	
	private static Long getInventoryOfProduct(Long productId, List<ReceiptNoteDTO> receiptNotes2Calc, List<OrderDTO> orders2Calc) {
		Long storedQuantity = getStoredQuantityOfProduct(productId, receiptNotes2Calc);
		Long soldQuantity = getSoldQuantityOfProduct(productId, orders2Calc);
		return storedQuantity - soldQuantity;
	}

	private static List<InvoiceDTO> getInvoicesBetweenDates(Date beginDate,
			Date endDate, int status, EmployeeDTO employee, EntityManager entityManager) {
		InvoiceDAO invoiceDAO = DAOFactory.createInvoiceDAO(entityManager);
		return invoiceDAO.findBetweenDates(beginDate, endDate, status, employee);
	}

	private static List<ReceiptNoteDTO> getReceiptNotesBetweenDates(
			Date beginDate, Date endDate, EntityManager entityManager) {
		ReceiptNoteDAO receiptNotesDAO = DAOFactory
				.createReceiptNoteDAO(entityManager);
		return receiptNotesDAO.findBetweenDates(beginDate, endDate);
	}

	private static List<OrderDTO> getOrdersBetweenDates(Date beginDate,
			Date endDate, EntityManager entityManager) {
		OrderDAO orderDAO = DAOFactory.createOrderDAO(entityManager);
		return orderDAO.findBetweenDates(beginDate, endDate);
	}

	public static List<ProductDTO> getAllActiveProducts(
			EntityManager entityManager) {
		ProductDAO productDAO = DAOFactory.createProductDAO(entityManager);
		return productDAO.findAllActive();
	}
	
	public static List<EmployeeDTO> getAllEmployees(
			EntityManager entityManager) {
		EmployeeDAO employeeDAO = DAOFactory.createEmployeeDAO(entityManager);
		return employeeDAO.findAll();
	}

	private static ProductDTO getActiveProductById(Long id,
			EntityManager entityManager) {
		ProductDAO productDAO = DAOFactory.createProductDAO(entityManager);
		return productDAO.findActiveById(id);
	}

	private static List<OrderDTO> getOrdersByDate(Date date,
			EntityManager entityManager) {
		OrderDAO orderDAO = DAOFactory.createOrderDAO(entityManager);
		return orderDAO.findByDate(date);
	}

	private static List<ReceiptNoteDTO> getReceiptNotesByDate(Date date,
			EntityManager entityManager) {
		ReceiptNoteDAO receiptNotes = DAOFactory
				.createReceiptNoteDAO(entityManager);
		return receiptNotes.findByDate(date);
	}
}
